home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc Development Framework / ODFDev / ODF / Found / FWExcLib / Sources / FWDelSta.cpp < prev    next >
Encoding:
Text File  |  1995-11-08  |  14.4 KB  |  434 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                FWDelSta.cpp
  4. //    Release Version:    $ 1.0d11 $
  5. //
  6. //    Copyright:    (c) 1993, 1995 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. #include "FWFound.hpp"
  11.  
  12. #ifndef FW_NATIVE_EXCEPTIONS
  13.  
  14. #ifndef      FWENVDEF_H
  15. #include "FWEnvDef.h"
  16. #endif
  17.  
  18. #ifndef   FWDELSTA_H
  19. #include "FWDelSta.h"
  20. #endif
  21.  
  22. #ifndef   FWEXCRUN_H
  23. #include "FWExcRun.h"
  24. #endif
  25.  
  26. #ifndef   FWPRIDEB_H
  27. #include "FWPriDeb.h"
  28. #endif
  29.  
  30. #ifndef   FWPRIMEM_H
  31. #include "FWPriMem.h"
  32. #endif
  33.  
  34. #ifndef   FWAUTODE_H
  35. #include "FWAutoDe.h"
  36. #endif
  37.  
  38. #ifndef   FWTRYBLO_H
  39. #include "FWTryBlo.h"
  40. #endif
  41.  
  42. #ifndef   FWSTDDEF_H
  43. #include "FWStdDef.h"
  44. #endif
  45.  
  46. #ifndef   FWCLAINF_H
  47. #include "FWClaInf.h"
  48. #endif
  49.  
  50. #if FW_LIB_EXPORT_PRAGMAS
  51. #pragma lib_export on
  52. #endif
  53.  
  54. #ifdef FW_BUILD_MAC
  55. #pragma segment BEL
  56. #endif
  57.  
  58. //========================================================================================
  59. // CLASS FW_CPrivDeleteStack
  60. //========================================================================================
  61.  
  62. //----------------------------------------------------------------------------------------
  63. // FW_CPrivDeleteStack::Initialize
  64. //----------------------------------------------------------------------------------------
  65. void FW_CPrivDeleteStack::Initialize(FW_SPrivExceptionGlobals& globals)
  66. {
  67.     globals.gCurrentContext = NULL;
  68.     globals.gBaseContext
  69.         = (FW_CPrivTryBlockContext *) ::FW_PrimitiveAllocateBlock(sizeof(FW_CPrivTryBlockContext));
  70.     FW_PRIV_ASSERT(globals.gBaseContext != NULL);
  71.     FW_CPrivTryBlockContext *baseContext
  72.         = new(globals.gBaseContext) FW_CPrivTryBlockContext(globals, 0);
  73.     FW_PRIV_ASSERT(baseContext == globals.gCurrentContext);
  74.     
  75. #ifdef FW_DEBUG
  76.     globals.gStackBase = (FW_CPrivDeleteEntry *)::FW_PrimitiveAllocateBlock(kStepByteSize+sizeof(FW_CPrivDeleteEntry));
  77. #else
  78.     globals.gStackBase = (FW_CPrivDeleteEntry *)::FW_PrimitiveAllocateBlock(kStepByteSize);
  79. #endif
  80.  
  81.     FW_PRIV_ASSERT(globals.gStackBase != NULL);
  82.  
  83.     globals.gCurrentStackSize = kNumberOfObjectsToGrowStack;
  84.     SetStackTop(globals, globals.gStackBase);
  85.     globals.gStackLimit = globals.gStackBase + kNumberOfObjectsToGrowStack;
  86.     
  87. #ifdef FW_DEBUG
  88.     CheckClassInvariants(globals);
  89. #endif
  90. }
  91.  
  92. //----------------------------------------------------------------------------------------
  93. // FW_CPrivDeleteStack::Terminate
  94. //----------------------------------------------------------------------------------------
  95. void FW_CPrivDeleteStack::Terminate()
  96. {
  97.     FW_SPrivExceptionGlobals& globals = FW_CExceptionTaskGlobals::GetExceptionGlobals();
  98.     ::FW_PrimitiveFreeBlock(globals.gStackBase);
  99.     ::FW_PrimitiveFreeBlock(globals.gBaseContext);
  100. }
  101.  
  102. //----------------------------------------------------------------------------------------
  103. // FW_CPrivDeleteStack::Push
  104. //----------------------------------------------------------------------------------------
  105. // Bottleneck
  106. void FW_CPrivDeleteStack::Push(void* aGuardOrObject,
  107.                             FW_CPrivDeleteEntry::__DeleteType type)
  108. {
  109.     FW_SPrivExceptionGlobals& globals = FW_CExceptionTaskGlobals::GetExceptionGlobals();
  110.  
  111. #ifdef FW_DEBUG
  112.     CheckClassInvariants(globals);
  113. #endif
  114.  
  115.     if (globals.gStackTop == globals.gStackLimit)
  116.     {
  117.         // Must grow stack before pushing next entry
  118.         _FW_StackEntries prevSize = globals.gCurrentStackSize;
  119.         _FW_StackEntries newSize = prevSize + kNumberOfObjectsToGrowStack;
  120. #ifdef FW_DEBUG
  121.         size_t newByteSize = (newSize+1) * sizeof(FW_CPrivDeleteEntry);
  122. #else
  123.         size_t newByteSize = newSize * sizeof(FW_CPrivDeleteEntry);
  124. #endif
  125.  
  126.         void* p = ::FW_PrimitiveResizeBlock((void*)globals.gStackBase, newByteSize);
  127.  
  128.         FW_PRIV_ASSERT(p != NULL);
  129.  
  130.         globals.gStackBase = (FW_CPrivDeleteEntry *)p;
  131.         globals.gStackTop = globals.gStackBase + prevSize;
  132.         globals.gCurrentStackSize = newSize;
  133.         globals.gStackLimit = globals.gStackBase + newSize;
  134.     }
  135.     FW_CPrivDeleteEntry * nextOpening = globals.gStackTop;
  136.  
  137.     nextOpening->fType = type;
  138.     nextOpening->fObject = (_FW_CAutoDestructObject *)aGuardOrObject;
  139.     if (aGuardOrObject != NULL)
  140.         nextOpening->fObjectVTable = *(void**)aGuardOrObject;
  141.  
  142.     SetStackTop(globals, nextOpening + 1);
  143.  
  144. #ifdef FW_DEBUG
  145.     if (type == FW_CPrivDeleteEntry::__kObject)
  146.         globals.gCurrentContext->fAutomaticsInMyScope++;
  147.     CheckClassInvariants(globals);
  148. #endif
  149. }
  150.  
  151. //----------------------------------------------------------------------------------------
  152. // FW_CPrivDeleteStack::IsClassExpectedInContext
  153. //----------------------------------------------------------------------------------------
  154. int FW_CPrivDeleteStack::IsClassExpectedInContext(FW_CPrivTryBlockContext *context,
  155.                                                FW_ClassInfoPtr  thrownType)
  156. {
  157.     FW_SPrivExceptionGlobals& globals = FW_CExceptionTaskGlobals::GetExceptionGlobals();
  158.  
  159.     FW_CPrivDeleteEntry * contextLimit = globals.gStackBase + context->fDeleteStackLevel;
  160.     FW_CPrivDeleteEntry * next = globals.gStackTop;
  161.  
  162.     FW_PRIV_ASSERT(globals.gStackBase != NULL);
  163.  
  164.     while (next > contextLimit)
  165.     {
  166.         next--;
  167.  
  168.         if (next->GetType() == FW_CPrivDeleteEntry::__kGuard)
  169.         {
  170.             FW_ClassInfoPtr  theGuardClass = next->GetGuard();
  171.             if (!theGuardClass || !thrownType->IsKindOf(theGuardClass))
  172.             {
  173.                 return 0;
  174.             }
  175.         }
  176.     }
  177.     return 1;
  178. }
  179.  
  180. //----------------------------------------------------------------------------------------
  181. // __CallDestructorWithNoVirtualBaseDelete (Macintosh version)
  182. //----------------------------------------------------------------------------------------
  183. #if defined(FW_BUILD_MAC) && defined(FW_NEED_DELETE_HACK)
  184. extern "C"
  185. {
  186.     #pragma parameter __CallDestructorWithNoVirtualBaseDelete(__D1)
  187.     void __CallDestructorWithNoVirtualBaseDelete(void *)
  188.         = {0x7000, 0x2f00, 0x2041, 0x2250, 0xd0e9, 0x0008,
  189.             0x2f08, 0x2041, 0x2050, 0x2268, 0x000c, 0x4e91, 0x508f};
  190. }
  191. /*
  192. 00000                              CallDestructorWithNoVirtualBaseDelete PROC
  193. 00000                                      ; D1 has object
  194. 00000   7000                               moveq    #0,d0                ; don't delete virtual bases
  195. 00002   2F00                               move.l    d0,-(a7)            ; arguement to destructor
  196. 00004   2041                               movea.l    d1,a0
  197. 00006   2250                               movea.l    (a0),a1                ; vtable for object
  198. 00008   D0E9 0008                          adda.w    8(a1),a0            ; get offset to start of object
  199. 0000C   2F08                               move.l    a0,-(a7)            ; push object address
  200. 0000E   2041                               movea.l    d1,a0
  201. 00010   2050                               movea.l    (a0),a0                ; vtable
  202. 00012   2268 000C                          movea.l    12(a0),a1            ; destructor address
  203. 00016   4E91                               jsr        (a1)
  204. 00018    508F                            addq.l    #8,a7                ; clean stack
  205. 0001A                                  ENDPROC
  206. */
  207. #endif
  208.  
  209. //----------------------------------------------------------------------------------------
  210. // __CallDestructorWithNoVirtualBaseDelete (Windows version)
  211. //----------------------------------------------------------------------------------------
  212. #if defined(__ZTCWIN__)  && defined(FW_NEED_DELETE_HACK)
  213. void __CallDestructorWithNoVirtualBaseDelete(void * p)
  214. {
  215.     asm(0xC4, 0x5E, 0x06);          //  les     BX, [BP+6]      ; ES:BX <-- pObject
  216.     asm(0x33, 0xC0);                //  xor     AX, AX          ; AX    <-- 0
  217.     asm(0x50);                      //  push    AX              ; Push dtor argument
  218.     asm(0x06);                      //  push    ES              ; Push pObject
  219.     asm(0x53);                      //  push    BX
  220.     asm(0x26, 0xC4, 0x1F);          //  les     BX, [ES:BX]     ; ES:BX <-- vmtPtr
  221.     asm(0x26, 0xFF, 0x5F, 0x04);    //  call    [DWORD ES:BX+4] ; Call the dtor
  222. }
  223. #endif
  224.  
  225. //----------------------------------------------------------------------------------------
  226. // FW_CPrivDeleteStack::PopOffAndDeleteObjectsInContext
  227. //----------------------------------------------------------------------------------------
  228. void FW_CPrivDeleteStack::PopOffAndDeleteObjectsInContext(FW_SPrivExceptionGlobals& globals,
  229.                                                         FW_CPrivTryBlockContext *context)
  230. {
  231. #ifdef FW_DEBUG
  232.     CheckClassInvariants(globals);
  233. #endif
  234.  
  235.     _FW_StackEntries offset = context->fDeleteStackLevel;
  236.  
  237.     FW_CPrivDeleteEntry * popLimit = globals.gStackBase + offset;
  238.     FW_CPrivDeleteEntry * popMe = globals.gStackTop;
  239.     FW_PRIV_ASSERT(popMe >= popLimit);
  240.     
  241.     globals.gIsThrowing = 1;
  242.  
  243.     while (popMe > popLimit)
  244.     {
  245.         popMe--;
  246.  
  247.         if (popMe->GetType() == FW_CPrivDeleteEntry::__kObject)
  248.         {
  249.             _FW_CAutoDestructObject * lastDeleted = popMe->GetObject();
  250.             FW_PRIV_ASSERT(lastDeleted != NULL);
  251.             *(void**)lastDeleted = popMe->fObjectVTable;
  252.     
  253.             // Global must be set properly before __Delete(), which calls PopIfTopEquals()
  254.             SetStackTop(globals, popMe+1);
  255. #if defined(FW_NEED_DELETE_HACK)
  256.             // Disabled, but may need to restore this code later.
  257.             __CallDestructorWithNoVirtualBaseDelete((void*)lastDeleted);
  258. #else
  259.             lastDeleted->__Delete();    // Virtual dispatch to object's destructor
  260. #endif
  261.     
  262.             // The destructor of the deleted object will have popped one or more objects 
  263.             // off the stack so we have to query the stack to find out who to pop next.
  264.             popMe = globals.gStackTop;
  265.         }
  266.     }
  267.  
  268.     FW_PRIV_ASSERT(popMe == popLimit);
  269.     SetStackTop(globals, popLimit);
  270.     globals.gIsThrowing = 0;
  271.  
  272. #ifdef FW_DEBUG
  273.     CheckClassInvariants(globals);
  274. #endif
  275. }
  276.  
  277.  
  278. //----------------------------------------------------------------------------------------
  279. // FW_CPrivDeleteStack::PopIfTopEquals
  280. //----------------------------------------------------------------------------------------
  281. // Bottleneck
  282. void FW_CPrivDeleteStack::PopIfTopEquals(_FW_CAutoDestructObject* anObject)
  283. {
  284.     FW_SPrivExceptionGlobals& globals = FW_CExceptionTaskGlobals::GetExceptionGlobals();
  285.  
  286. #ifdef FW_DEBUG
  287.     CheckClassInvariants(globals);
  288. #endif
  289.  
  290.     FW_CPrivTryBlockContext *context = globals.gCurrentContext;
  291.     _FW_StackEntries offset = context->fDeleteStackLevel;
  292.     FW_CPrivDeleteEntry * popLimit = globals.gStackBase + offset;
  293.     FW_CPrivDeleteEntry * popMe = globals.gStackTop;
  294.     FW_PRIV_ASSERT(popMe > popLimit);
  295.  
  296.     // Normally, the top item on the stack will be the entry for anObject.
  297.     // However, we may be deleting out of order, and there may be guards.
  298.     // So, we must clean any gaurds and previously deleted items off the top
  299.     // of the stack.  If the first kObject entry is our object, then we clean
  300.     // it off too and exit.  If the first kObject entry is not our object, then
  301.     // we need to search through the stack for our object and mark it deleted.
  302.     // During the search, the stack top is not changed.
  303.  
  304.     // Clean off guards and deleted items.  Stack top is changed.
  305.     while (popMe > popLimit)
  306.     {
  307.         popMe--;
  308.         if (popMe->GetType() == FW_CPrivDeleteEntry::__kObject)
  309.             break;
  310.     }
  311.     
  312.     // There must still be at list one entry in this context.
  313.     FW_PRIV_ASSERT(popMe >= popLimit);
  314.     
  315.     // And the top one must be an undeleted object entry.
  316.     FW_PRIV_ASSERT(popMe->GetType() == FW_CPrivDeleteEntry::__kObject);
  317.  
  318.     FW_Boolean objectDeleted = FALSE;
  319.     if (popMe->GetObject() == anObject)
  320.     {
  321.         // All is cool.  First kObject entry is our object.  Pop off entry.
  322.         SetStackTop(globals, popMe);
  323.         objectDeleted = TRUE;
  324.     }
  325.     else
  326.     {
  327.         // Need to remember where the stack top is now located.
  328.         SetStackTop(globals, popMe+1);
  329.  
  330.         // Destroying out of order.  Search for our object and mark it destroyed.
  331.         // Do not change stack top.
  332.  
  333.         while (popMe > popLimit)
  334.         {
  335.             popMe--;
  336.             if (popMe->GetType() == FW_CPrivDeleteEntry::__kObject && popMe->GetObject() == anObject)
  337.             {
  338.                 popMe->SetType(FW_CPrivDeleteEntry::__kDeleted);
  339.                 objectDeleted = TRUE;
  340.                 break;
  341.             }
  342.         }
  343.     }
  344.  
  345. #ifdef FW_DEBUG
  346.     if (objectDeleted)
  347.         context->fAutomaticsInMyScope--;
  348.     CheckClassInvariants(globals);
  349. #endif
  350. }
  351.  
  352. //----------------------------------------------------------------------------------------
  353. // FW_CPrivDeleteStack::PopGuard
  354. //----------------------------------------------------------------------------------------
  355. FW_ClassInfoPtr  FW_CPrivDeleteStack::PopGuard()
  356. {
  357.     FW_SPrivExceptionGlobals& globals = FW_CExceptionTaskGlobals::GetExceptionGlobals();
  358.  
  359. #ifdef FW_DEBUG
  360.     CheckClassInvariants(globals);
  361. #endif
  362.  
  363.     FW_CPrivDeleteEntry * popMe = globals.gStackTop - 1;
  364.     FW_ClassInfoPtr result = popMe->GetGuard();
  365.     SetStackTop(globals, popMe);
  366.  
  367. #ifdef FW_DEBUG
  368.     CheckClassInvariants(globals);
  369. #endif
  370.  
  371.     return result;
  372. }
  373.  
  374. #ifdef FW_DEBUG
  375. //----------------------------------------------------------------------------------------
  376. // FW_CPrivDeleteStack::CheckClassInvariants
  377. //----------------------------------------------------------------------------------------
  378. void FW_CPrivDeleteStack::CheckClassInvariants(FW_SPrivExceptionGlobals& globals)
  379. {
  380.     // Ensure class invariants
  381.     FW_PRIV_ASSERT(globals.gStackBase != NULL);
  382.     FW_PRIV_ASSERT(globals.gStackBase <= globals.gStackTop);
  383.     FW_PRIV_ASSERT(globals.gStackTop <= globals.gStackLimit);
  384.     FW_PRIV_ASSERT(globals.gCurrentStackSize >= kNumberOfObjectsToGrowStack);
  385.     FW_PRIV_ASSERT(globals.gStackBase+globals.gCurrentStackSize == globals.gStackLimit);
  386.     FW_PRIV_ASSERT(globals.gStackTop->GetType() == FW_CPrivDeleteEntry::__kInvalid);
  387.  
  388.     FW_CPrivTryBlockContext *context = globals.gCurrentContext;
  389.     if (context != NULL)
  390.     {
  391.         context->CheckClassInvariants(globals);
  392.         FW_PRIV_ASSERT(RelativeTopOfStack(globals) >= context->fDeleteStackLevel);
  393.         FW_PRIV_ASSERT(RelativeTopOfStack(globals)-context->fDeleteStackLevel >= context->fAutomaticsInMyScope);
  394.     }
  395. }
  396. #endif
  397.  
  398. //========================================================================================
  399. // CLASS FW_CPrivThrowGuard
  400. //========================================================================================
  401.  
  402. //----------------------------------------------------------------------------------------
  403. // FW_CPrivThrowGuard::FW_CPrivThrowGuard
  404. //----------------------------------------------------------------------------------------
  405. FW_CPrivThrowGuard::FW_CPrivThrowGuard()
  406. {
  407.     FW_CPrivDeleteStack::Push((FW_ClassInfoPtr ) NULL);
  408. #ifdef FW_DEBUG
  409.     fGuardClass = (FW_ClassInfoPtr ) NULL;
  410. #endif
  411. }
  412.  
  413. //----------------------------------------------------------------------------------------
  414. // FW_CPrivThrowGuard::FW_CPrivThrowGuard
  415. //----------------------------------------------------------------------------------------
  416. FW_CPrivThrowGuard::FW_CPrivThrowGuard(FW_ClassInfoPtr  guard)
  417. {
  418.     FW_CPrivDeleteStack::Push(guard);
  419. #ifdef FW_DEBUG
  420.     fGuardClass = guard;
  421. #endif
  422. }
  423.  
  424. //----------------------------------------------------------------------------------------
  425. // FW_CPrivThrowGuard::~FW_CPrivThrowGuard
  426. //----------------------------------------------------------------------------------------
  427. FW_CPrivThrowGuard::~FW_CPrivThrowGuard()
  428. {
  429.     FW_ClassInfoPtr  aClass = FW_CPrivDeleteStack::PopGuard();
  430.     FW_PRIV_ASSERT(aClass == fGuardClass);
  431. }
  432.  
  433. #endif // FW_NATIVE_EXCEPTIONS
  434.